using Microsoft.Win32;
using Godot;
using Godot.Collections;
using NLua;
using System;
using System.Collections.Generic;
using Array = Godot.Collections.Array;
using Object = Godot.Object;
using MaterialDictionary = System.Collections.Generic.Dictionary<string, SWMaterial>;
using System.Linq;

public class Materials
{
	public static void GravityBlock(UpdataTickEvent e, String name)
	{
		BlockData block = e.world.GetBlock(e.Position - new Vector3I(0, 1));
		if (block.GetMaterial().CanReplace)
		{
			e.world.SetBlock(e.Position + new Vector3I(0, -1), Materials.GetBlockMaterial(name));
			e.world.SetBlock(e.Position, Materials.Air);
		}
	}
	private static void WaterBlock(UpdataTickEvent e)
	{

	}
	public static readonly List<SWMaterial> AllMaterials = new List<SWMaterial>();
	public static List<ItemMateria> WoodTool = RegisteryItemHelp.RegisteryTool(
		"wood",
		"木",
		1,
		16
	);
	public static List<ItemMateria> StoneTool = RegisteryItemHelp.RegisteryTool(
		"stone",
		"石",
		1,
		32
	);
	public static List<ItemMateria> PebbleTool = RegisteryItemHelp.RegisteryTool(
		"pebble",
		"燧石",
		2,
		128,
		true,
		true,
		true,
		false,
		false,
		false
	);
	public static List<ItemMateria> IronTool = RegisteryItemHelp.RegisteryTool(
		"iron",
		"铁",
		3,
		256
	);


	public static ItemMateria ChunkRemove = RegistryItem(
	   new ItemMateria("chunkremove")
	   .SetDisplayName("区块破坏者")
	   .SetPlayerUseItem((PlayerUseItemEvent e) =>
	   {
		   var chunk = e.world.ActiveChunk;
		   for (int x = 0; x < 16; x++)
			   for (int y = 0; y < 16; y++)
			   {
				   chunk.SetBlock(x, y,e.player.layer, Air);
			   }
		   return true;
	   })
   ).AddLore("一次破坏整个区块！")
   , Stick = RegistryItem(
	   new ItemMateria("stick")
	   .SetDisplayName("木棍")
		.SetFuel(20)
   ),
   Twig = RegistryItem(
	   new ItemMateria("twig")
	   .SetDisplayName("树枝")
	   .SetFuel(20)
   ),
   Charcoal = RegistryItem(
	   new ItemMateria("charcoal")
	   .SetDisplayName("木炭")
	   .SetFuel(800)
   ),
   Bucket = RegistryItem(
	   new ItemMateria("bucket", new ImageSet { name = "buckets", coord = new Vector2(0, 0) })
	   .SetDisplayName("桶")
	   .SetMaxAmount(16)
	   .SetPlayerUseItem((PlayerUseItemEvent e) =>
	   {
		   if (e.block.GetMaterial() is FluidBlock)
		   {
			   if (e.player.store.AddItem(new ItemStack(Materials.GetItemMateria("bucket_" + e.block.Name))))
			   {
				   if (e.slotType == PlayerUseItemEvent.PlayerUseItemSlotType.Curosr)
					   e.player.store.SubCurosrItemAmount(1);
				   else if (e.slotType == PlayerUseItemEvent.PlayerUseItemSlotType.Hand)
					   e.player.store.SubAmount(e.player.store.getIndex(), 1);
				   e.world.SetBlock(e.Position, Materials.Air);
			   }

		   }
		   else
		   {
			   if (e.block.blockEntity == null) return true;
			   FluidData fd = e.block.blockEntity.GetFluid(0);
			   if (fd != null && fd.SubAmount(1000))
			   {
				   if (e.player.store.AddItem(new ItemStack(Materials.GetItemMateria("bucket_" + fd.name))))
				   {
					   if (e.slotType == PlayerUseItemEvent.PlayerUseItemSlotType.Curosr)
						   e.player.store.SubCurosrItemAmount(1);
					   else if (e.slotType == PlayerUseItemEvent.PlayerUseItemSlotType.Hand)
						   e.player.store.SubAmount(e.player.store.getIndex(), 1);
				   }
				   else
				   {
					   fd.AddAmount(1000);
				   }
			   }
		   }
		   //    if (e.block.Name == "water")
		   //    {
		   //        if (e.slotType == PlayerUseItemEvent.PlayerUseItemSlotType.Curosr)
		   //            e.player.store.SubCurosrItemAmount(1);
		   //        else if (e.slotType == PlayerUseItemEvent.PlayerUseItemSlotType.Hand)
		   //            e.player.store.SubAmount(e.player.store.getIndex(), 1);
		   //        e.player.store.AddItem(new ItemStack(Materials.GetItemMateria("bucket_water")));
		   //        e.world.SetBlock(e.worldLocation, Materials.Air);
		   //    }
		   //    else
		   //    {
		   //        FluidData fd = e.block.GetFluid("water");
		   //        if (fd != null && fd.SubAmount(1000))
		   //        {
		   //            if (e.slotType == PlayerUseItemEvent.PlayerUseItemSlotType.Curosr)
		   //                e.player.store.SubCurosrItemAmount(1);
		   //            else if (e.slotType == PlayerUseItemEvent.PlayerUseItemSlotType.Hand)
		   //                e.player.store.SubAmount(e.player.store.getIndex(), 1);
		   //            e.player.store.AddItem(new ItemStack(Materials.GetItemMateria("bucket_water")));
		   //        }
		   //    }

		   return true;
	   })
   ),
   Bucket_Water = RegistryItem(
	   new ItemMateria("bucket_water", new ImageSet { name = "buckets", coord = new Vector2(1, 0) })
	   .SetDisplayName("水桶")
	   .SetMaxAmount(1)
	   .SetPlayerUseItem((PlayerUseItemEvent e) =>
	   {
		   if (e.block.Name == "air")
		   {
			   e.item = e.item.SetAmount(e.item.Amount - 1);
			   e.player.store.AddItem(new ItemStack(Materials.GetItemMateria("bucket")));
			   e.world.SetBlock(e.Position, Materials.Water);
		   }
		   else
		   {
			   FluidData fd = e.block.GetFluid("water");
			   if (fd != null && fd.AddAmount(1000))
			   {
				   if (e.slotType == PlayerUseItemEvent.PlayerUseItemSlotType.Curosr)
					   e.player.store.SubCurosrItemAmount(1);
				   else if (e.slotType == PlayerUseItemEvent.PlayerUseItemSlotType.Hand)
					   e.player.store.SubAmount(e.player.store.getIndex(), 1);
				   e.player.store.AddItem(new ItemStack(Materials.GetItemMateria("bucket")));
			   }
		   }

		   return true;
	   }
   )),
		Clay = RegistryItem(
	   new ItemMateria("clay")
	   .SetDisplayName("粘土")
   ),
		Red_Bricks = RegistryItem(
	   new ItemMateria("red_bricks")
	   .SetDisplayName("粘土砖")
   ),
		Raw_Red_Bricks = RegistryItem(
	   new ItemMateria("raw_red_bricks")
	   .SetDisplayName("生粘土砖")
   ),
		Wood_Big_Stick = RegistryItem(
	   new ItemMateria("wood_big_stick")
	   .SetDisplayName("粗木棍")
   ),
	   Wood_Crank = RegistryItem(
	   new ItemMateria("wood_crank")
	   .SetDisplayName("木曲柄")
   ),
		Wood_Big_Gear = RegistryItem(
	   new ItemMateria("wood_big_gear")
	   .SetDisplayName("木制大齿轮")
   ),
		Wood_Gear = RegistryItem(
	   new ItemMateria("wood_gear")
	   .SetDisplayName("木制齿轮")
   ),
		Salt = RegistryItem(
	   new ItemMateria("salt")
	   .SetDisplayName("盐")
   ),
	   Wood_Mold = RegistryItem(
	   new ItemMateria("wood_mold")
	   .SetDisplayName("木制模具")
   ),
	   Pebble = RegistryItem(
	   new ItemMateria("pebble")
	   .SetDisplayName("燧石")
   ),
	   Pebble_Pickaxe_Head = RegistryItem(
	   new ItemMateria("pebble_pickaxe_head")
	   .SetDisplayName("燧石镐头")
	   .SetMaxAmount(16)
   ),
	   Pebble_Axe_Head = RegistryItem(
	   new ItemMateria("pebble_axe_head")
	   .SetDisplayName("燧石斧头")
	   .SetMaxAmount(16)

   ),
	   Pebble_Shovel_Head = RegistryItem(
	   new ItemMateria("pebble_shovel_head")
	   .SetDisplayName("燧石铲头")
	   .SetMaxAmount(16)

   ),

	   Twine = RegistryItem(
	   new ItemMateria("twine")
	   .SetDisplayName("麻绳")
   )
		,
	   grass_rope = RegistryItem(
	   new ItemMateria("grass_rope")
	   .SetDisplayName("草绳")
   )
		,
	   Latch = RegistryItem(
	   new ItemMateria("latch")
	   .SetDisplayName("插销")
   )
				,
	   Wood_Sheet = RegistryItem(
	   new ItemMateria("wood_sheet")
	   .SetDisplayName("木薄板")
   ),
	   Wood_Bolt = RegistryItem(
	   new ItemMateria("wood_bolt")
	   .SetDisplayName("木螺栓")
   )
   ;
	public static readonly AirBlock Air = RegistryBlock<AirBlock>();
	public static readonly StoneBlock Stone = RegistryBlock<StoneBlock>();
	public static readonly ClayBlock Clay_Block = RegistryBlock<ClayBlock>();
	public static readonly DirtBlock Dirt = RegistryBlock<DirtBlock>();
	public static readonly GrassBlock Grass = RegistryBlock<GrassBlock>();
	public static readonly CobblestoneBlock Cobblestone = RegistryBlock<CobblestoneBlock>();
	public static readonly OakLogBlock OakLog = RegistryBlock<OakLogBlock>();
	public static readonly WoodPlankBlock Wood_Plank = RegistryBlock<WoodPlankBlock>();
	public static readonly HalfWoodPlankBlock Half_Wood_Plank = RegistryBlock<HalfWoodPlankBlock>();
	public static readonly FoliageBlock Foliage = RegistryBlock<FoliageBlock>();
	public static readonly RockBlock Rock = RegistryBlock<RockBlock>();
	public static readonly BushesBlock Bushes = RegistryBlock<BushesBlock>();
	public static readonly FluidBlock Water = RegistryBlock(new FluidBlock("water"));
	public static readonly SandBlock Sand = RegistryBlock<SandBlock>();
	public static readonly SandStoneBlock SandStone = RegistryBlock<SandStoneBlock>();
	public static readonly GravelBlock Gravel = RegistryBlock<GravelBlock>();
	public static readonly AlgaeBlock Algae = RegistryBlock<AlgaeBlock>();
	public static readonly ClayFurnaceBlock Clay_Furnace = RegistryBlock<ClayFurnaceBlock>();
	public static readonly FurnaceBlock Furnace = RegistryBlock<FurnaceBlock>();
	public static readonly ChestBlock Chest = RegistryBlock<ChestBlock>();
	public static readonly HopperBlock Hopper = RegistryBlock<HopperBlock>();
	public static readonly CopperFluidPipeBlock Copper_Fluid_Pipe = RegistryBlock<CopperFluidPipeBlock>();
	public static readonly SteamGeneratorBlock Steam_Generator = RegistryBlock<SteamGeneratorBlock>();
	public static readonly SteamBoilerTankBlock Steam_Boiler_Tank = RegistryBlock<SteamBoilerTankBlock>();
	public static readonly SteamCrusherBlock Steam_Crusher = RegistryBlock<SteamCrusherBlock>();
	public static readonly FarmlandBlock Farmland = RegistryBlock<FarmlandBlock>();
	public static readonly WheatCropsBlock Wheat_Crops = RegistryBlock<WheatCropsBlock>();
	public static readonly CampfireBlock Campfire = RegistryBlock<CampfireBlock>();
	public static readonly RedStoneBlock_Block Redstone_block = RegistryBlock<RedStoneBlock_Block>();
	public static readonly RedstoneStringBlock Redstone_String = RegistryBlock<RedstoneStringBlock>();
	public static readonly RedStoneLampBlock Redstone_Lamp = RegistryBlock<RedStoneLampBlock>();
	public static readonly RedMushroomBlock Red_Mushroom = RegistryBlock<RedMushroomBlock>();
	public static readonly PistonBlock Piston = RegistryBlock<PistonBlock>();
	
	
	public static readonly WhiteMushroomBlock White_Mushroom = RegistryBlock<WhiteMushroomBlock>();
	public static readonly BrichlogBlock Brichlog = RegistryBlock<BrichlogBlock>();
	public static readonly BrichFoliageBlock BrichFoliage = RegistryBlock<BrichFoliageBlock>();
	public static readonly TurnipBlock Turnip = RegistryBlock<TurnipBlock>();
	public static readonly CarrotBlock Carrot = RegistryBlock<CarrotBlock>();
	public static readonly VinesBlock Vines = RegistryBlock<VinesBlock>();
	public static readonly CactusBlock Cactus = RegistryBlock<CactusBlock>();
	public static readonly WiltedShrubsBlock Wilted_Shrubs = RegistryBlock<WiltedShrubsBlock>();
	public static readonly EchinopsisTubifloraBlock Echinopsis_Tubiflora = RegistryBlock<EchinopsisTubifloraBlock>();
	public static readonly CoconutPalmLogBlock Coconut_Palm_Log = RegistryBlock<CoconutPalmLogBlock>();
	public static readonly CoconutPalmFoliageBlock Coconut_Palm_Foliage = RegistryBlock<CoconutPalmFoliageBlock>();
	public static readonly WoodenBarrelBlock Wooden_Barrel = RegistryBlock<WoodenBarrelBlock>();
	public static readonly IronDrumBlock Iron_Drum = RegistryBlock<IronDrumBlock>();
	public static readonly SteamBlock_Block SteamBlock = RegistryBlock<SteamBlock_Block>();


	public static readonly BlockMaterial Iron_Ore = RegistryOre("iron", "铁", new ImageSet { name = "ingots", coord = new Vector2(0, 0) });
	public static readonly BlockMaterial Copper_Ore = RegistryOre("copper", "铜", new ImageSet { name = "ingots", coord = new Vector2(1, 0) });
	public static readonly BlockMaterial Tin_Ore = RegistryOre("tin", "锡", new ImageSet { name = "ingots", coord = new Vector2(2, 0) });
	public static readonly BlockMaterial Gold_Ore = RegistryOre("gold", "金", new ImageSet { name = "ingots", coord = new Vector2(3, 0) });

	public static Recipes Recipes = new Recipes();
	public static SWMaterial GetMaterial(String name, MaterialType Type)
	{
		for (int i = 0; i < AllMaterials.Count; i++)
		{
			if (AllMaterials[i].Name == name && AllMaterials[i].Type == Type)
			{
				return AllMaterials[i];
			}
		}
		return null;
	}
	public static SWMaterial GetMaterial(int index, MaterialType type)
	{
		int i = 0;
		foreach (SWMaterial swm in AllMaterials)
		{
			if (swm.Type == type)
			{
				if (i == index)
				{
					return swm;
				}
				i++;
			}
		}
		return null;
	}
	public static ItemMateria GetItemMateria(int index)
	{
		SWMaterial swm = GetMaterial(index, MaterialType.Item);
		return swm != null ? (ItemMateria)swm : null;
	}
	public static ItemMateria GetItemMateria(String name)
	{
		SWMaterial swm = GetMaterial(name, MaterialType.Item);
		return swm != null ? (ItemMateria)swm : null;
	}
	public static BlockMaterial GetBlockMaterial(String name)
	{
		SWMaterial swm = GetMaterial(name, MaterialType.Block);
		return swm != null ? (BlockMaterial)swm : null;
	}
	public static T RegistryItem<T>(T material) where T : SWMaterial
	{
		AllMaterials.Add(material);
		return (T)material;
	}
	public static ItemMateria RegistryItem(ItemMateria material)
	{
		AllMaterials.Add(material);
		return material;
	}
	public static BlockMaterial RegistryOre(String id, String name, ImageSet imageSet = null)
	{
		RegistryItem(new ItemMateria($"{id}_ingot", new ImageSet { name = imageSet.name, coord = imageSet.coord + new Vector2(0, 1) }).SetDisplayName($"{name}锭"));
		RegistryItem(new ItemMateria($"{id}_plate", new ImageSet { name = imageSet.name, coord = imageSet.coord + new Vector2(0, 2) }).SetDisplayName($"{name}板"));
		RegistryItem(new ItemMateria($"{id}_stick", new ImageSet { name = imageSet.name, coord = imageSet.coord + new Vector2(0, 3) }).SetDisplayName($"{name}棍"));
		return RegistryBlock(
			new BlockMaterial($"{id}_ore")
			.SetDisplayName($"{name}矿石")
			.SetImageSet(imageSet)
		);
	}
	public static T RegistryBlock<T>(ItemMateria item = null) where T : BlockMaterial
	{
		T block = Activator.CreateInstance(typeof(T)) as T;
		block.ItemMateria = RegistryItem(item != null ? item : new ItemMateria(block.Name).
		SetDisplayName(block.DisPlayName).
		SetBlock(true).
		SetHide(block.hide).
		SetImageSet(block.imageset)
		);
		block.ItemMateria.Fuel = block.Fule;
		block.ItemMateria.SetBlock(true);
		AllMaterials.Add(block);
		BlockTileSet.RegisterTile(block);
		return (T)block;
	}
	public static T RegistryBlock<T>(T block, ItemMateria item = null) where T : BlockMaterial
	{
		block.ItemMateria = RegistryItem(item != null ? item : new ItemMateria(block.Name).
		SetDisplayName(block.DisPlayName).
		SetBlock(true).
		SetHide(block.hide).
		SetImageSet(block.imageset)
		);
		block.ItemMateria.SetBlock(true);
		AllMaterials.Add(block);
		BlockTileSet.RegisterTile(block);
		return (T)block;
	}
	public static BlockMaterial RegistryBlock(BlockMaterial block, ItemMateria item = null)
	{
		block.ItemMateria = RegistryItem(item != null ? item : new ItemMateria(block.Name).
		SetDisplayName(block.DisPlayName).
		SetBlock(true).
		SetHide(block.hide).
		SetImageSet(block.imageset));
		block.ItemMateria.SetBlock(true);
		AllMaterials.Add(block);
		BlockTileSet.RegisterTile(block);
		return block;
	}
	public static Recipe GetRecipe(int id)
	{
		return Recipes.recipes[id];
	}
	public static Recipe GetRecipe(BlockMaterial material)
	{
		for (int i = 0; i < Recipes.recipes.Count; i++)
		{
			Recipe r = Recipes.recipes[i];
			if (r.block.Name == material.Name)
			{
				return r;
			}
		}
		return null;
	}
	public static Recipe GetRecipe(BlockMaterial material, ItemStack res)
	{
		if (res == null) return null;
		List<Recipe> recipes = GetRecipes(material);
		foreach (Recipe recipe in recipes)
		{
			if (recipe.Res[0].equalMaterial(res))
			{
				return recipe;
			}
		}
		return null;
	}
	public static List<Recipe> GetRecipes(BlockMaterial material)
	{
		List<Recipe> rl = new List<Recipe>();
		for (int i = 0; i < Recipes.recipes.Count; i++)
		{
			Recipe r = Recipes.recipes[i];

			if (r.block == material)
			{
				rl.Add(r);
			}
		}
		return rl;
	}
	//未完成
	[Obsolete]
	public static void Load()
	{
		GD.Print("[注册方块]");
		List<String> files = new List<string>();
		Directory dir = new Directory();
		if (dir.Open("Config/Block") != Error.Ok)
		{
			dir.MakeDirRecursive("Config/Block");
		}
		dir.ListDirBegin(true);
		String filename = dir.GetNext();
		while (filename != "")
		{
			if (!dir.CurrentIsDir())
			{
				if (filename.Contains(".json"))
					files.Add(filename);
			}
			filename = dir.GetNext();
		}
		dir.ListDirEnd();
		//

		foreach (String fn in files)
		{
			GD.Print("加载方块:" + fn);
			File f = new File();
			if (f.Open("Config/Block/" + fn, File.ModeFlags.Read) != Error.Ok)
			{
				continue;
			}

			List<Dictionary> dicts = new List<Dictionary>();
			object result = JSON.Parse(f.GetAsText()).Result;
			f.Close();
			if (result is Array)
			{
				Array array = (Array)result;
				for (int i = 0; i < array.Count; i++)
				{
					dicts.Add((Dictionary)array[i]);
				}
			}
			if (result is Dictionary)
			{
				dicts.Add((Dictionary)result);
			}

			for (int index = 0; index < dicts.Count; index++)
			{

				Dictionary dict = dicts[index];
				BlockMaterial bm = new BlockMaterial(dict["name"] as string);
				if (dict.Contains("displayname")) bm.DisPlayName = dict["displayname"] as string;
				if (dict.Contains("group")) bm.Group = dict["name"] as string;
				if (dict.Contains("durable")) bm.Durable = dict["name"].ToInt();
				if (dict.Contains("canbreak")) bm.CanBreak = Convert.ToBoolean(dict["canbreak"] as string);
				if (dict.Contains("state")) bm.SetStateMax(dict["state"].ToInt());
				if (dict.Contains("full")) bm.Collide = Convert.ToBoolean(dict["full"] as string);
				if (dict.Contains("View")) bm.View = Convert.ToBoolean(dict["view"] as string);
				if (dict.Contains("script"))
				{
					String script = "Config/Script/" + dict["script"] as string;
					bm.script = new Lua();
					bm.script.DoFile(script);
				}
				GD.Print($"[Register Block]:{bm.Name}");
				Materials.RegistryBlock(bm);
			}
		}
	}
}
